import express from 'express'
import fs from 'fs'


import { JSONFilePreset } from 'lowdb/node'

import path, { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import multer from 'multer'

const app = express()
// Read or create db.json
const defaultData = {
  administrators:[],
  groups:[],
  articles: []

}

const db = await JSONFilePreset('db.json', defaultData)


/**
 * 跨域
 */

app.all('*', function (req, res, next) {
  console.log(req.originalUrl)
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Headers', '*');
  res.header('Access-Control-Allow-Methods', '*');
  res.header('Access-Control-Max-Age',3600);
  next();
});

//临时密钥
const  secretKeys=['XA6677E','8B0411','521baicai',"T04764860296"]
//当前密钥索引
let   currentSecretKeyIndex=0;
/**
 * 拦截后台(/admin)
 */
app.all('/admin/*', function (req, res, next) {
  console.info(`URL:${req.originalUrl},X-Custom-Token:${req.get('X-Custom-Token')},请求方法:${req.method}`)
  if(req.method!=="GET"){
    if(req.get('X-Custom-Token')!==secretKeys[currentSecretKeyIndex]){
      res.json({
        code:401,
        message:"没有Token令牌，禁止入内，麻烦去登录页申请",
        data:null
      })
      return;
    }
  }

  next();

});



const dir ="/home/website/md/";
app.use(express.json())
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
console.log(__dirname)

/**
 * 开放public目录为静态资源目录，可直接通过http://访问
 */
app.use('/public', express.static('public'));


/**
 * 静态资源访问 - 用于访问上传的资料
 */
app.use('/uploads', express.static(path.join(__dirname, '../uploads')));



/**
 * 自定义上传规则
 * @type {DiskStorage}
 */
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, path.join(__dirname,'public/'));    // 保存的路径，备注：需要自己创建
  },
  filename: function (req, file, cb) {
    // 将保存文件名设置为 时间戳，比如 1478521468943.png
    cb(null,  Date.now() +file.originalname.substring(file.originalname.lastIndexOf('.')) );
  }
});


//构建上传对象
const  upload  =multer({storage})


/**
 * 上传单个图片
 * imgFile 上传图片的key（文件字段名）
 */
app.post("/uploadImage",upload.single("imgFile"),(req,res)=>{

  res.json({
    code:200,
    message:"上传文件成功",
    data:{
      originalName:req.file.originalname,
      fileName:req.file.filename,
      relative: 'public/'
    }
  })


})


/**
 * 静态图片访问
 */
/*
app.get("/static/:imageUrl",(req,res)=>{
  const filePath = path.resolve(__dirname, `./public/${req.params.imageUrl}`);
  console.log(filePath)
  res.set( 'content-type', "image/png");//设置返回类型
  const stream = fs.createReadStream(filePath);
  const responseData = [];//存储文件流
  if (stream) {//判断状态
    stream.on( 'data', function( chunk ) {
      responseData.push( chunk );
    });
    stream.on( 'end', function() {
      const finalData = Buffer.concat( responseData );
      res.write( finalData );
      res.status(200);
      res.end();
    });

    stream.on('error', function(err) {
      res.write( Buffer.concat( responseData ) );
      res.status(200);
      res.end();
    });

  }

})
*/

app.post('/login', (req, res) => {

  const  admin  =db.data.administrators.find((item)=>item.password===req.body.password)
  if(admin){
    res.json({
      code:200,
      message:"恭喜你登录成功",
      data:secretKeys[currentSecretKeyIndex]
    })

  }else{
    res.json({
      code:500,
      message:"用户名和密码错误",
      data:null
    })
  }


})



/**
 * 技术文章分类访问
 */

app.get('/groups', (req, res) => {

  res.json({
    code:200,
    message:"获取分类列表成功",
    data:db.data.groups
  })

})


/**
 * 技术文章列表访问
 */
app.get('/articles', (req, res) => {
  const  arts  =db.data.articles.filter((item)=>item.groupId===req.query.gid)
  res.json({
    code:200,
    message:"获取文章列表成功",
    data:arts
  })

})

/**
 *技术文章内容访问
 */
app.get('/find', (req, res) => {
  const  article=   db.data.articles.find((item)=>item.id===req.query.id)
  const text = fs.readFileSync(dir+article.location,{encoding:"utf-8"})
  res.json({
    code:200,
    message:"获取文件成功",
    data:text
  })

})
/**
 * 发布文章
 */
app.post('/admin/submit', (req, res) => {

  //写入文件
  fs.writeFile(dir+req.body.title+".md",req.body.text, {
    encoding:"utf8",
    flag:"w",
    mode:0o666
  },(err)=>{
    if (err)
      console.log(err);
    else {
      //把文章信息写入数据库表
      db.data.articles.splice(0,0,{
        id:Date.now().toString(),
        title:req.body.title,
        content:"",
        location:`${req.body.title}.md`,
        createDate:new Date().toLocaleDateString(),
        author:"1",
        groupId:req.body.groupId

      })
      db.write()

    }
  });



  res.json({
    code:200,
    message:"文件已经异步发布",
    data:''
  })

})


app.put('/admin/update', (req, res) => {
  //数据库文章
  const  article=   db.data.articles.find((item)=>item.id===req.body.id)
  //写入文件
  fs.writeFile(dir+article.location,req.body.content, {
    encoding:"utf8",
    flag:"w",
    mode:0o666
  },(err)=>{
    if (err)
      console.log(err);
    else {
      //把文章信息写入数据库表  。但是清空内容，因为内容存储到md文件中了
      Object.assign(article,req.body,{content:""})
      db.write()

    }
  });

  res.json({
    code:200,
    message:"文件已经异步发布",
    data:''
  })

})




/**
 * 技术文章列表访问
 */
app.get('/admin/articles', (req, res) => {
  res.json({
    code:200,
    message:"获取文章列表成功",
    data:db.data.articles
  })

})

app.get('/admin/find', (req, res) => {
  const  article=   db.data.articles.find((item)=>item.id===req.query.id)
  const  text =fs.readFileSync(dir + article.location, { encoding: "utf-8" });
  res.json({
    code:200,
    message:"获取文件成功",
    data:Object.assign({},article,{content:text})
  })

})



/**
 * 删除
 */
app.delete('/admin/delete/:id', (req, res) => {
  const  index=   db.data.articles.findIndex((item)=>item.id===req.params.id)
  db.data.articles.splice(index,1)
  db.write()
  res.json({
    code:200,
    message:"删除文件成功",
    data:null
  })

})



/**
 * 遍历 public 目录下的所有文件
 */
app.get('/admin/screenshots', async (req, res) => {
  try {
    const publicDir = path.join(__dirname, 'public');
    const files = await fs.promises.readdir(publicDir);

    const fileDetails = [];

    for (const file of files) {
      const filePath = path.join(publicDir, file);
      const stat = await fs.promises.stat(filePath);

      // 获取文件扩展名作为类型
      const extname = path.extname(file).toLowerCase();
      let fileType = 'file';

      // 判断常见图片类型
      if (['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg'].includes(extname)) {
        fileType = 'image';
      }
      // 判断常见视频类型
      else if (['.mp4', '.webm', '.mov', '.avi'].includes(extname)) {
        fileType = 'video';
      }
      // 判断常见音频类型
      else if (['.mp3', '.wav', '.ogg', '.flac'].includes(extname)) {
        fileType = 'audio';
      }

      fileDetails.push({
        name: file,
        path: `/public/${file}`,
        size: stat.size, // 文件大小（字节）
        type: fileType,  // 文件类型
        mtime: stat.mtime.toISOString(), // 最后修改时间
      });
    }

    res.json({
      code: 200,
      message: "获取文件列表成功",
      data: fileDetails
    });
  } catch (err) {
    console.error('读取文件列表时出错:', err);
    res.status(500).json({
      code: 500,
      message: "获取文件列表失败",
      data: null
    });
  }
});




/**
 * 自定义资料上传规则 - 保留原始文件名（安全处理版）
 * @type {DiskStorage}
 */
const resourceStorage = multer.diskStorage({
  destination: function (req, file, cb) {
    // 获取 public 目录的父级目录，然后创建 uploads 目录
    const uploadDir = path.join(__dirname, './uploads');

    // 确保目录存在（递归创建）
    fs.mkdirSync(uploadDir, { recursive: true });

    cb(null, uploadDir);
  },
  filename: (req, file, cb) => {
    // 解析原始文件名（包含中文）
    const originalName = file.originalname;

    // 仅移除操作系统禁止的非法字符（保留中文、字母、数字、下划线、短横线、点）
   // const sanitizedName = originalName.replace(/[\\/:"*?<>|]/g, ''); // 移除Windows非法字符，保留中文

    // 直接使用处理后的原始文件名（如需唯一化，可追加时间戳）
    // cb(null, sanitizedName); // 不修改文件名（可能重复）
    cb(null, `${Date.now()}-${originalName}${path.extname(originalName)}`); // 推荐：原始名+时间戳，避免重复
  }
});

// 允许的文件类型白名单（根据需求调整）
const allowedMimeTypes = [
  // 文档类
  'application/pdf',
  'application/msword',
  'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  'application/vnd.ms-excel',
  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  'application/vnd.openxmlformats-officedocument.presentationml.presentation',
  'text/plain',

  // 图片类（如果需要）
  'image/jpeg',
  'image/png',
  'image/gif',
  'image/webp',

  // 其他常见类型
  'application/zip',
  'application/x-zip-compressed',
];

// 构建带文件类型校验的上传中间件
const uploadResource = multer({
  storage: resourceStorage,
  limits: {
    fileSize: 1024 * 1024 * 50, // 50MB文件大小限制
  },
  fileFilter: (req, file, cb) => {
    if (!allowedMimeTypes.includes(file.mimetype)) {
      const error = new Error('不支持的文件类型');
      error.code = 'UNSUPPORTED_FILE_TYPE';
      return cb(error, false);
    }
    cb(null, true);
  }
});

/**
 * 上传资料接口 - 带原始文件名支持
 * file 上传文件的字段名
 */
app.post("/admin/uploadResource", uploadResource.single("file"), (req, res) => {
  // 错误处理（文件类型/大小超出限制）
  if (!req.file && req.error) {
    const error = req.error;
    if (error.code === 'LIMIT_FILE_SIZE') {
      return res.status(400).json({
        code: 400,
        message: "文件大小超过限制（最大50MB）",
        data: null
      });
    } else if (error.code === 'UNSUPPORTED_FILE_TYPE') {
      return res.status(400).json({
        code: 400,
        message: "不支持的文件类型",
        supportedTypes: allowedMimeTypes,
        data: null
      });
    } else {
      return res.status(500).json({
        code: 500,
        message: "上传过程中发生错误",
        data: null
      });
    }
  }

  // 获取上传后的文件信息
  const fileInfo = {
    originalName: req.file.originalname, // 原始完整文件名（用于展示）
    savedName: req.file.filename, // 安全处理后的存储文件名
    safeName: req.file.filename.split('-').slice(0, -1).join('-'), // 安全处理后的原始名部分
    uniqueSuffix: req.file.filename.split('-').pop().split('.')[0], // 唯一标识符部分
    extension: path.extname(req.file.filename).toLowerCase(), // 文件扩展名
    size: req.file.size, // 文件大小（字节）
    mimetype: req.file.mimetype, // MIME类型
    url: `/uploads/${req.file.filename}`, // 访问URL
    uploadTime: new Date().toISOString() // 上传时间
  };

  res.json({
    code: 200,
    message: "资料上传成功",
    data: fileInfo
  });
});

/**
 * 遍历上传的资料文件（最简版本）
 * 返回最近上传的文件在最前面，无分页，无类型筛选
 */
app.get('/admin/resources', async (req, res) => {
  try {
    const uploadDir = path.join(__dirname, './uploads');
    const files = await fs.promises.readdir(uploadDir, { withFileTypes: true });

    // 处理文件信息并按修改时间降序排序（最新的在前）
    const fileList = await Promise.all(
      files
        .filter(dirent => dirent.isFile()) // 只保留文件
        .map(async dirent => {
          const filePath = path.join(uploadDir, dirent.name);
          const stat = await fs.promises.stat(filePath);

          return {
            filename: dirent.name, // 原始文件名
            path: `/uploads/${dirent.name}`, // 访问路径
            size: stat.size, // 文件大小（字节）
            mtime: stat.mtime.getTime(), // 修改时间戳（毫秒）
            createdAt: stat.ctime.getTime() // 创建时间戳
          };
        })
    );

    // 按修改时间降序排序（最新的在前）
    fileList.sort((a, b) => b.mtime - a.mtime);

    res.json({
      code: 200,
      message: "获取文件列表成功",
      data: fileList
    });
  } catch (err) {
    console.error('读取文件列表失败:', err);
    res.status(500).json({
      code: 500,
      message: "服务器错误，获取文件列表失败",
      data: null
    });
  }
});



/**
 * 下载 uploads 目录下的文件（简单版）
 * @route GET /download/upload/:fileName
 * @param {string} fileName - 文件名（需 URL 编码，如中文需转义）
 */
app.get('/admin/download/file/:fileName', (req, res) => {
  // 解码文件名（处理中文等特殊字符）
  const fileName = decodeURIComponent(req.params.fileName);
  // 拼接文件绝对路径（注意：uploads 目录可能在 public 同级或其他位置，需根据实际路径调整）
  const filePath = path.join(__dirname, './uploads', fileName); // 假设 uploads 与 public 同级

  // 检查文件是否存在
  if (!fs.existsSync(filePath)) {
    return res.status(404).json({
      code: 404,
      message: '文件不存在',
      data: null
    });
  }

  // 设置响应头（强制下载，支持中文文件名）
  res.setHeader('Content-Disposition', `attachment; filename="${encodeURIComponent(fileName)}"`);
  res.setHeader('Content-Type', 'application/octet-stream'); // 通用二进制流类型

  // 创建文件流并返回
  const stream = fs.createReadStream(filePath);
  stream.pipe(res).on('error', (err) => {
    console.error('文件下载错误:', err);
    res.status(500).json({
      code: 500,
      message: '文件下载失败',
      data: null
    });
  });
});




/**
 * 删除 uploads 目录下的文件
 * @route DELETE /admin/delete/file/:fileName
 * @param {string} fileName - 文件名（需 URL 编码，如中文需转义）
 */
app.delete('/admin/delete/file/:fileName', (req, res) => {
  // 解码文件名（处理中文等特殊字符）
  const fileName = decodeURIComponent(req.params.fileName);
  // 拼接文件绝对路径
  const filePath = path.join(__dirname, './uploads', fileName);

  // 检查文件是否存在
  if (!fs.existsSync(filePath)) {
    return res.status(404).json({
      code: 404,
      message: '文件不存在',
      data: null
    });
  }

  // 安全检查：确保不删除目录或系统文件
  const stats = fs.statSync(filePath);
  if (stats.isDirectory()) {
    return res.status(400).json({
      code: 400,
      message: '不能删除目录',
      data: null
    });
  }


  // 执行文件删除
  fs.unlink(filePath, (err) => {
    if (err) {
      console.error('文件删除失败:', err);
      return res.status(500).json({
        code: 500,
        message: '文件删除失败',
        data: null
      });
    }

    // 删除成功
    res.status(200).json({
      code: 200,
      message: '文件删除成功',
      data: { fileName }
    });
  });
});



/**
 * 端口
 * @type {number}
 */
const port = 3001
/**
 * 启动服务
 */
app.listen(port, () => {
  console.log(`Server is up  on port ${port}`)
})